/* bbtweet
 * 
 */


package net.masker.bbtweet;

import java.io.IOException;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.StreamConnection;

import net.rim.device.api.io.http.HttpProtocolConstants;
import net.rim.device.api.notification.NotificationsConstants;
import net.rim.device.api.notification.NotificationsManager;
import net.rim.device.api.system.ApplicationManager;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.AutoTextEditField;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.NumericChoiceField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.component.PasswordEditField;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.component.Status;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.blackberry.api.browser.URLEncodedPostData;
import net.rim.blackberry.api.homescreen.HomeScreen;
import net.rim.blackberry.api.options.*;

public class bbtweet extends UiApplication 
{
	private static String updateURL = "http://twitter.com/statuses/update.xml";
	private static bbtweetProperties properties;

	//Notifications ID net.masker.bbtweet.bbtweet.NOTIFICATIONS_ID_1
	public static final long NOTIFICATIONS_ID_1 = 0xc4340ba571f1f6c9L;
	
	//Dialog updatingDlg = new Dialog("Updating Status",null,null,0,Bitmap.getBitmapResource("img/bbTweet_jde.png"));
	Dialog errDlg = new Dialog("Error occcurred!",null,null,0,Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION));
	//Dialog successDlg = new Dialog("Success!",null,null,0,Bitmap.getBitmapResource("img/bbTweet1_jde.png"));
    
	bbtweetConnectionManager _connectionManager = new bbtweetConnectionManager();
	updateManager _updateManager = new updateManager();
	
	// Cache menu items
	
	private MenuItem _about = new MenuItem("About", 0x00050100, 300)
	{
		public void run()
		{
			pushScreen(new bbtweetAboutScreen());
		}
	};
	
	private MenuItem _options = new MenuItem("Options", 0x00050000, 200)
	{
		public void run()
		{
			pushScreen(new bbtweetOptionsScreen());
		}
	};

/* Not using this for now
	private void notifyUser(String data)
	{
	  UiEngine ui = Ui.getUiEngine();
	  Screen screen = new Dialog(Dialog.D_OK, data, Dialog.OK,
	    Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION),
	    Manager.VERTICAL_SCROLL);
	  ui.pushGlobalScreen(screen, 1, ui.GLOBAL_QUEUE);
	} */
	
	public bbtweet(boolean startup)
	{
	    // main instance of application
		if (startup)
		{
        	// Set Rollover icon for versions < 4.7
        	final Bitmap icon = Bitmap.getBitmapResource("img/bbTweet_jde.png");
        	final Bitmap rollIcon = Bitmap.getBitmapResource("img/bbTweet1_jde.png");
        	invokeLater(new Runnable()
        	{
        		public void run()
        		{
	        		ApplicationManager myApp = ApplicationManager.getApplicationManager();
	        		boolean wait = true;
	        		while (wait)
	        		{
	        			// Check if startup complete
	        			if (myApp.inStartup())
	        			{
	        				// sleep 1 sec, wait for startup to complete
	        				try
	        				{
	        					Thread.sleep(1000);
	        				}
	        				catch (Exception e)
	        				{
	        					// Couldn't sleep
	        				}
	        			}
	        			else
	        			{
	        				// Startup complete
	        				// Set icons
	        				HomeScreen.updateIcon(icon, 0);
	        				HomeScreen.setRolloverIcon(rollIcon, 0);
	        				wait = false;
	        			}
	        		}
        		}
        	});
        	
        	// Start the connection manager
        	_connectionManager.start();
        	
		}
		else
		{
			// Push the main screen instance onto the UI stack for rendering.
			pushScreen(new bbtweetUpdateScreen());
			
			// If Options are not initialized, push Options screen onto the UI stack
			properties = bbtweetProperties.fetch();
			if (properties.getAuthenticationHash() == null)
				pushScreen(new bbtweetOptionsScreen());
		}
	}

	public static void main(String[] args)
    {
        if( args != null && args.length > 0 && args[0].equals("startup"))
        {            
            // Startup 
        	// Clear stale state info
        	properties = bbtweetProperties.fetch();
        	properties.setConnectionManagerStarted(false);
        	properties.save();
        	
        	// Register Notification Source
        	NotificationsManager.registerSource( NOTIFICATIONS_ID_1, new Object()
            {
                public String toString()
                {
                    return "bbtweet";
                }
            }, NotificationsConstants.DEFAULT_LEVEL);
        	
        	// Start background connection thread
        	bbtweet theApp = new bbtweet(true);
        	theApp.enterEventDispatcher();
        }
        else
        {       
            //Enter GUI
        	//Create new instance of app & start app on event thread
        	bbtweet theApp = new bbtweet(false);
        	theApp.enterEventDispatcher();
        }
    }
    
    final class bbtweetAboutScreen extends MainScreen
    {
    	public bbtweetAboutScreen()
    	{
    		// Refresh properties
    		properties = bbtweetProperties.fetch();
    		
    		// Have the icon when clicked show the Application status
            LabelField title = new LabelField("About bbtweet" , LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
            setTitle(title);
            
            add(new RichTextField("bbtweet", Field.NON_FOCUSABLE));
            add(new RichTextField("Better Twitter integration with native BlackBerry Apps", Field.NON_FOCUSABLE));
            add(new RichTextField("Version: 0.1 SVN"));
            add(new SeparatorField());
            add(new RichTextField("State: " + (properties.isBbtweetEnabled() ? "Enabled" : "Disabled"),Field.NON_FOCUSABLE));
            add(new RichTextField("Running: " + (properties.isConnectionManagerStarted() ? "Yes" : "No"),Field.NON_FOCUSABLE));
            add(new RichTextField("H: " + properties.getAuthenticationHash(),Field.NON_FOCUSABLE));
            add(new RichTextField("Update Retrieval: " + properties.getBbtweetStatusMessage()));
    	}
    	
    	private MenuItem _reset = new MenuItem("Reset lastID", 100, 200)
    	{
    		public void run()
    		{
    			properties = bbtweetProperties.fetch();
    			properties.setLastID(0);
    			properties.save();
    			Dialog.inform("Cleared last ID");
    		}
    	};
    	
    	private MenuItem _back = new MenuItem("Back", 200, 100)
    	{
    		public void run()
    		{
    			onClose();
    		}
    	};
    	
    	protected void makeMenu(Menu menu, int instance)
    	{
    		menu.add(_reset);
    		menu.add(_back);
    		menu.addSeparator();
    		super.makeMenu(menu, instance);
    	}
    }
    
    final class bbtweetUpdateScreen extends MainScreen
    {
    	
    	private AutoTextEditField statusUpdateTextField;
    	
    	public bbtweetUpdateScreen()
    	{	
    		// Set Screen Title
            LabelField title = new LabelField("What are you doing?" , LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
            setTitle(title);
            
            //add(new RichTextField("What are you doing?", Field.NON_FOCUSABLE));
            statusUpdateTextField = new AutoTextEditField();
            properties = bbtweetProperties.fetch();
            statusUpdateTextField.setText(properties.getStatusUpdate());
            statusUpdateTextField.setCursorPosition(statusUpdateTextField.getTextLength());
            add(statusUpdateTextField);
    	}
    	
    	protected void makeMenu(Menu menu, int instance)
    	{
    		menu.add(_update);
    		menu.add(_options);
    		menu.add(_about);
    		super.makeMenu(menu, instance);
    	}
    	
    	private MenuItem _update = new MenuItem("Update", 0x00040000, 100)
    	{
    		public void run()
    		{
    			//Check that credentials have been entered
    			properties = bbtweetProperties.fetch();
    			if (properties.getAuthenticationHash() == null)
    			{
    				Dialog.alert("Cannot update status until credentials are entered on Options screen");
    				return;
    			}
    			
    			//updatingDlg.show();
    			Status.show("Updating Status", Bitmap.getBitmapResource("img/bbTweet_jde.png"), 2000);
    			invokeLater(new Runnable()
    			{
    				public void run()
    				{
    					properties = bbtweetProperties.fetch();
            			properties.setStatusUpdate(statusUpdateTextField.getText());
            			properties.setPushStatusUpdate(true);
            			properties.save();
            			

            			
            			// open stream and post
            			try
            			{
            				URLEncodedPostData post = new URLEncodedPostData("", false);
            				post.append("source", "bbtweet");
            				post.append("status", properties.getStatusUpdate());
            				StreamConnection s = (StreamConnection)Connector.open(updateURL + "?" + post.toString());
            				HttpConnection httpConn = (HttpConnection)s;
            	            httpConn.setRequestProperty(HttpProtocolConstants.HEADER_AUTHORIZATION,"Basic "
            	            		+ properties.getAuthenticationHash());
            	            httpConn.setRequestMethod("POST");
            	            
            	            int status = httpConn.getResponseCode();
            	            if (status != HttpConnection.HTTP_OK)
            	            {
            	            	// updatingDlg.close();
            	            	errDlg.doModal();
            	            	//notifyUser("Failed to update status!"); 
            	            }
            	            else
            	            {
            	    			Status.show("Success!", Bitmap.getBitmapResource("img/bbTweet1_jde.png"), 1000);
            	            	properties = bbtweetProperties.fetch();
                	            properties.setPushStatusUpdate(false);
                	            properties.setStatusUpdate("");
                	            properties.save();
                	            statusUpdateTextField.clear(0);
                	            //updatingDlg.close();
                	            //successDlg.show();
                	            // assume success, maybe?
            	            }
            	            
            			}
            			catch (IOException e) 
            	        {
            	        	properties = bbtweetProperties.fetch();
            	        	properties.setBbtweetStatusMessage(e.toString());
            	        	properties.save();
            	        	//notifyUser("Failed to update status!");
            	        	// updatingDlg.close();
        	            	errDlg.doModal();
            	        }
        			
    				}
    			});
    		}
    	}; 
    	
    	
    	
    	public boolean onSavePrompt()
    	{
    		properties = bbtweetProperties.fetch();
    		properties.setStatusUpdate(statusUpdateTextField.getText());
    		properties.save();
    		
    		statusUpdateTextField = null;
    		return true;
    	}
    }
    
    final class bbtweetOptionsScreen extends MainScreen
    {
    	
    	private ObjectChoiceField enabledChoice;
        private EditField usernameEdit;
        private PasswordEditField passwordEdit;
        private NumericChoiceField intervalChoice;
        private bbtweetProperties properties;
    	
    	public bbtweetOptionsScreen()
    	{
    		// Set Screen Title
            LabelField title = new LabelField("bbtweet Options" , LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
            setTitle(title);
    		
    		//Read in the properties from the persistent store.
            properties = bbtweetProperties.fetch();

            //Get the current values and push the screen
            usernameEdit = new EditField("Username: ", properties.getUsername(),
            		BasicEditField.DEFAULT_MAXCHARS, BasicEditField.NO_NEWLINE);
            add(usernameEdit);
            
            passwordEdit = new PasswordEditField("Password: ", "",
            		PasswordEditField.DEFAULT_MAXCHARS, 0);
            add(passwordEdit);
            
            Object[] enabledChoices = {"Disabled", "Enabled"};
            int enabledSelection = properties.isBbtweetEnabled() ? 1 : 0;
            enabledChoice = new ObjectChoiceField("Update Retrieval: ", enabledChoices, enabledSelection);
            add(enabledChoice);
            
            intervalChoice = new NumericChoiceField("Update interval: ", 1, 20, 1);
            intervalChoice.setSelectedValue(properties.getUpdateInterval());
            add(intervalChoice);
    	}
    	
    	public boolean isDataValid()
    	{
    		// Detect special case where username was updated and password needs to be re-entered to compute hash
    		// Allow hash to be cleared out if username is cleared
        	if ((usernameEdit.getText().compareTo(properties.getUsername()) != 0) && (!(passwordEdit.getTextLength() > 0))
        			&& !("".equals(usernameEdit.getText())))
        	{
        		Dialog.alert("Please enter your password");
        		return false;
        	}
        	else if (("".equals(usernameEdit.getText())) && (enabledChoice.getSelectedIndex() == 1)) 
        	{ // Must have credentials if Enabled
        		Dialog.alert("Please enter credentials to enable update retrieval");
        		return false;
        	}
        	else
        	{
        		// As long as password is entered when username is changed, all other data should be valid
        		return true;
        	}
    	}
    	
    	public void save()
        {
        	//save properties
            properties.setBbtweetEnabled(enabledChoice.getSelectedIndex() == 1);
            properties.setUsername(usernameEdit.getText());
            // Only update password if changed
            if (passwordEdit.getTextLength() > 0)
            	properties.setPassword(passwordEdit.getText());
            properties.setUpdateInterval(intervalChoice.getSelectedValue());

            //Write changes.
            properties.save();
            
            //Start Connection Manger if necessary
            if (properties.isBbtweetEnabled() && !properties.isConnectionManagerStarted())
            	_connectionManager.start();
            
            //Clean up

            enabledChoice = null;
            usernameEdit = null;
            passwordEdit = null;
            intervalChoice = null;
            properties = null;
        }
    	
    	protected void makeMenu(Menu menu, int instance)
    	{
    		menu.add(_save);
    		super.makeMenu(menu, instance);
    	}
    	
    	private MenuItem _save = new MenuItem("Save", 100, 10)
    	{
    		public void run()
    		{
    			if (onSave())
    				close();
    		}
    	};
    	
    }
    

}


